#! /usr/bin/python3

"""
Analyze "{{ ping_log }}"
"""

import sys
import logging
import queue

FILE = "{{ ping_log }}"
TAKE_LAST_N_ATTEMPTS = 10
WARN_TIME = 6*60
ERR_TIME = 20*60

EXIT_OK = 0
EXIT_WARN = 1
EXIT_CRITICAL = 2
EXIT_UNKNOWN = 3

logging.basicConfig(
    level=logging.INFO,
    format='%(message)s',
    handlers=[logging.StreamHandler(sys.stdout)],
)
LOG = logging.getLogger()


class Context:  # pylint: disable=too-few-public-methods
    """ Just a context structure """
    status = EXIT_OK


def set_status(context, status):
    """
    Set a CTX.status to STATUS, if STATUS is worse than the actual
    """
    if context.status < status:
        context.status = status


def warning(context, msg, *args):
    """ Throw a nagios warning """
    LOG.warning(msg, *args)
    set_status(context, EXIT_WARN)


def error(context, msg, *args):
    """ Throw a nagios error """
    LOG.error(msg, *args)
    set_status(context, EXIT_CRITICAL)


def _main(context):
    last_lines = queue.Queue()

    with open(FILE) as file:
        for line in file:
            last_lines.put(line)

            if len(last_lines.queue) > TAKE_LAST_N_ATTEMPTS:
                last_lines.get()

    builds_checked = 0
    while last_lines.queue:
        # re-set the state, only the last matters
        context.status = EXIT_OK

        builds_checked += 1

        line = last_lines.get()
        values = {
            "start": None,
            "stop": None,
            "exit_status": -1,
            "build_id": 0,
        }

        for value in line.split():
            key, value = value.split('=')
            values[key] = value

        if values["start"] is None or values["stop"] is None or values["exit_status"] == -1:
            LOG.error("some values not set in %s", FILE)
            sys.exit(EXIT_CRITICAL)

        build_id = values["build_id"]
        start = int(values["start"])
        stop = int(values["stop"])
        took = stop - start
        if took > ERR_TIME:
            error(context, "Build %s took %ss (allowed %s)", build_id, took,
                  WARN_TIME)
        elif took > WARN_TIME:
            warning(context, "Build %s took %ss (allowed %s)", build_id, took,
                    WARN_TIME)

        if int(values["exit_status"]) != 0:
            error(context, "Exit status is %s (non-zero) for build ID %s",
                  values["exit_status"], values["build_id"])

    if context.status == EXIT_OK:
        LOG.info("The last build %s for copr-ping succeeded", build_id)


if __name__ == "__main__":
    ctx = Context()
    try:
        _main(ctx)
        sys.exit(ctx.status)
    except Exception:  # pylint: disable=broad-except
        LOG.exception("UNKNOWN EXCEPTION")
        sys.exit(EXIT_CRITICAL)
